﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Resources;
using System.Reflection;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.PropertySystem;
using PaintDotNet.IndirectUI;
using LibFiltr;

namespace AnisotropyFilterPlugin
{
    public class PluginSupportInfo : IPluginSupportInfo
    {
        public string Author
        {
            get
            {
                return "UrFU Radiotechnical facultet";
            }
        }
        public string Copyright
        {
            get
            {
                return "Copyright © 2011";
            }
        }

        public string DisplayName
        {
            get
            {
                return "AnisotropyFilterPlugin";
            }
        }

        public Version Version
        {
            get
            {
                return base.GetType().Assembly.GetName().Version;
            }
        }

        public Uri WebsiteUri
        {
            get
            {
                return new Uri("http://paintnoisefilter.codeplex.com/");
            }
        }
    }

    [PluginSupportInfo(typeof(PluginSupportInfo), DisplayName = "AnisotropyFilter")]
    public class AnisotropyFilterPlugin : PropertyBasedEffect
    {
        private AnisotropyFilter _filter;
        int _not_processed_rois;
        Surface _tmp;
        bool _iter_init_done, _tmp_copied;
        private System.Object lockThis = new System.Object();
        int ep;

        public static string StaticName
        {
            get
            {
                return "Anisotropy filter";
            }
        }

        public static Image StaticIcon
        {
            get
            {
                return new Bitmap(typeof(AnisotropyFilterPlugin), "AnisotropyFilterPluginIcon.png");
            }
        }

        public static string StaticSubMenuName
        {
            get
            {
                return "Filtr"; // Use for no submenu
                // return "My SubMenu"; // Use for custom submenu
            }
        }

        public AnisotropyFilterPlugin()
            : base(StaticName, StaticIcon, StaticSubMenuName, EffectFlags.None)
        {
            _iter_init_done = false;
            Random r = new Random();
            //file.WriteLine("contstructor");
        }

        protected override PropertyCollection OnCreatePropertyCollection()
        {
            List<Property> props = new List<Property>();

            return new PropertyCollection(props);
        }

        protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
        {
            ControlInfo configUI = CreateDefaultConfigUI(props);

            return configUI;
        }

        protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
        {
            base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
        }


        protected override void OnCustomizeConfigUIWindowProperties(PropertyCollection props)
        {
            // Change the effect's window title
            props[ControlInfoPropertyNames.WindowTitle].Value = "Anisotropy filter";
            base.OnCustomizeConfigUIWindowProperties(props);
        }

        protected override unsafe void OnRender(Rectangle[] rois, int startIndex, int length)
        {
            if (length == 0) return;

            lock (lockThis)
            {
                if (!_iter_init_done)
                {
                    // init thread sync stuff
                    _not_processed_rois = rois.GetLength(0);
                    _tmp = DstArgs.Surface.Clone();
                    _filter = new AnisotropyFilter();
                    _iter_init_done = true;
                    ep = 0;
                }
            }

            // first iteration
            for (int i = startIndex; i < startIndex + length; ++i)
            {
                Render(_tmp, SrcArgs.Surface, rois[i]);
                _not_processed_rois -= rois[i].Bottom - rois[i].Top;
            }
            // thread sync
            _not_processed_rois -= length;
            WaitForAll();
            _iter_init_done = false;
            // other iterations
            for (int ep = 0; ep < 10; ep++)
            {
                lock (lockThis)
                {
                    if (!_iter_init_done)
                    {
                        _not_processed_rois = rois.GetLength(0);
                        _tmp_copied = false;
                        _iter_init_done = true;
                    }
                }
                for (int i = startIndex; i < startIndex + length; ++i)
                {
                    Render(DstArgs.Surface, _tmp, rois[i]);
                }
                // thread sync
                _not_processed_rois -= length;
                WaitForAll();
                lock (lockThis)
                {
                    if (!_tmp_copied)
                    {
                        _tmp = DstArgs.Surface.Clone();
                        _tmp_copied = true;
                        _iter_init_done = false;
                    }
                }
            }
        }

        void WaitForAll()
        {
            while (_not_processed_rois > 0)
                ;
        }

        void Render(Surface dst, Surface src, Rectangle rect)
        {
            Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

            _filter.Filter(dst, src, selection, rect);
        }
    }
}
